package com.examination.utils;

import com.examination.bean.Selection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 反射类
 */
public class ReflectionUtil {
    public static void main(String[] args) throws Exception {
        Selection selection = new Selection();
        Selection object = setObjectValue(selection,"id",1l);
        System.out.println(object.getId());
//        test3(selection);
//        test1();
    }
    /**
     * 把一个字符串的第一个字母大写、效率是最高的、
     */
    private static String getMethodName(String fildeName) throws Exception {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }
    /**
     *轻量反射orm:对某对象object 设置 数据库的列对应的xx值
     * @param object 对这个对象设置值
     * @param columnName choice_info 数据库列名，规则是和javaBean对应的名称，如果有下划线的会自动处理，下划线对应的是javaBean驼峰规则
     * @param columnVal 数据库对应的choice_info字段值，这个是数据库的字段对应的值，TODO 日期未处理
     * @return
     * @throws Exception
     */
    public static <T> T setObjectValue(T object,String columnName,Object columnVal) throws Exception {
        //choice_info
        if(null != columnName && columnName.length() > 0){
            // 拿到该类
            Class clz = object.getClass();
            // 获取实体类的所有属性，返回Field数组
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {// --for() begin
                String fieldName = field.getName();//字段名称 choiceInfo
                //满足名称字段和实体字段完全一致情况，或数据库字段去掉"_"后依然相同情况才向后进行匹配
                if(!(columnName.toLowerCase().equals(fieldName.toLowerCase()) || columnName.replaceAll("_","").toLowerCase().equals(fieldName.toLowerCase()))){
                    continue;
                }
                System.out.println(field.getGenericType());//打印该类的所有属性类型
                // 如果类型是String
                if (field.getGenericType().toString().equals(
                        "class java.lang.String")) { // 如果type是类类型，则前面包含"class "，后面跟类名
                    // 拿到该属性的gettet方法
                    /**
                     *  public void setChoiceInfo(String choiceInfo) {
                     *         this.choiceInfo = choiceInfo;
                     *     }
                     */
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),String.class);
                    Object res = m.invoke(object,(String)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Integer
                if (field.getGenericType().toString().equals(
                        "class java.lang.Integer")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Integer.class);
                    Object res = m.invoke(object,(Integer)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Long
                if (field.getGenericType().toString().equals(
                        "class java.lang.Long")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Long.class);
                    Object res = m.invoke(object,(Long)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Float
                if (field.getGenericType().toString().equals(
                        "class java.lang.Float")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Float.class);
                    Object res = m.invoke(object,(Float)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Double
                if (field.getGenericType().toString().equals(
                        "class java.lang.Double")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Double.class);
                    Object res = m.invoke(object,(Double)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Boolean 是封装类
                if (field.getGenericType().toString().equals(
                        "class java.lang.Boolean")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + fieldName,Boolean.class);
                    Object res = m.invoke(object,(Boolean)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Short
                if (field.getGenericType().toString().equals(
                        "class java.lang.Short")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Short.class);
                    Object res = m.invoke(object,(Short)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Character
                if (field.getGenericType().toString().equals(
                        "class java.lang.Character")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Character.class);
                    Object res = m.invoke(object,(Character)columnVal);// 调用setXxxYxx设置值
                    break;
                }
                // 如果类型是Date
                if (field.getGenericType().toString().equals(
                        "class java.util.Date")) {
                    Method m = (Method) object.getClass().getMethod(
                            "set" + getMethodName(fieldName),Date.class);
                    Object res = m.invoke(object,(java.util.Date)columnVal);// 调用setXxxYxx设置值
                    break;
                }
            }//for() --end
        }
        return object;
    }

    /**
     * 反射盗用方法
     * @param className
     * @param methodName
     * @param params
     * @return
     */
    public static Object invoke(String className, String methodName, Object...params){
        try {
            Class<?> c = Class.forName(className);
            Object obj = c.newInstance();
            Method[] methods = c.getDeclaredMethods();
            Method callMethod = null;
            for(Method method:methods){
                if(method.getName().equals(methodName)){
                    callMethod = method;
                    break;
                }
            }
            callMethod.setAccessible(true);
            return callMethod.invoke(obj, params);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return  null;
    }
}
